import { Meta, MethodMetaContext } from './Meta';
import axios, { AxiosInstance } from '@ohos/axios';
import { RequestFactory } from './RequestFactory';
import { AxiosCall, Call } from './Call';
import { Request } from './Request';
import { HttpMethod } from './HttpConstants';
import { Interceptor } from './Interceptor';

export class HttpDecorator implements Call.Factory {
  private static default: HttpDecorator
  protected readonly _interceptors: ReadonlyArray<Interceptor>
  private axiosInstance: AxiosInstance;


  constructor(builder: HttpDecorator.Builder) {
    this.axiosInstance = builder.axios ?? axios.create()
    this._interceptors = builder.interceptors
  }

  get interceptors(): ReadonlyArray<Interceptor> {
    return this._interceptors
  }

  get axios(): AxiosInstance {
    return this.axiosInstance
  }

  static getDefault(): HttpDecorator {
    if (!HttpDecorator.default) {
      HttpDecorator.default = new HttpDecorator.Builder().build()
    }
    return HttpDecorator.default
  }

  create<T>(type: (new () => T)): T {
    const instance = this
    let api = new type()
    return new Proxy(api as any, {
      get(target, prop, receiver) {
        // let result = Reflect.get(target, prop, receiver)
        return (...args: any) => {
          let methodContext = new MethodMetaContext(target, prop.toString(), args)
          const request = RequestFactory.parseMetas(instance, methodContext).create()
          return instance.newCall(request)
        }
      }
    }) as any
  }

  newCall(request: Request): Call {
    return new AxiosCall(this, request)
  }
}

export namespace HttpDecorator {
  export class Builder {
    axios: AxiosInstance
    interceptors: Array<Interceptor> = []

    setAxios(axios: AxiosInstance): Builder {
      this.axios = axios
      return this
    }

    addInterceptor(interceptor: Interceptor): Builder {
      this.interceptors.push(interceptor)
      return this
    }

    build(): HttpDecorator {
      return new HttpDecorator(this)
    }
  }
}

type MethodPathMappingMeta = (path?: string) => MethodDecorator;
type HttpMappingMeta = (value: {
  method: HttpMethod,
  path?: string
}) => MethodDecorator;
type HeadersMappingMeta = (value: Array<string>) => MethodDecorator;
type ParameterPathMappingMeta = (path?: string) => ParameterDecorator;
type ParameterValueMappingMeta = (value: string) => ParameterDecorator;

export type HttpMappingValue = {
  method: HttpMethod,
  path?: string
}


//请求方法
export const GET = Meta.createMethodMeta<MethodPathMappingMeta>()

export const HEAD = Meta.createMethodMeta<MethodPathMappingMeta>()

export const POST = Meta.createMethodMeta<MethodPathMappingMeta>()

export const PUT = Meta.createMethodMeta<MethodPathMappingMeta>()

export const DELETE = Meta.createMethodMeta<MethodPathMappingMeta>()

export const TRACE = Meta.createMethodMeta<MethodPathMappingMeta>()

export const CONNECT = Meta.createMethodMeta<MethodPathMappingMeta>()

export const OPTIONS = Meta.createMethodMeta<MethodPathMappingMeta>()

export const HTTP = Meta.createMethodMeta<HttpMappingMeta>()

//请求参数
export const Path = Meta.createParameterMeta<ParameterPathMappingMeta>()

export const Query = Meta.createParameterMeta<ParameterPathMappingMeta>()

export const Body = Meta.createParameterMeta<ParameterDecorator>()

export const Header = Meta.createParameterMeta<ParameterValueMappingMeta>()

export const HeaderMap = Meta.createParameterMeta<ParameterDecorator>()

export const Headers = Meta.createMethodMeta<HeadersMappingMeta>()

export const QueryMap = Meta.createParameterMeta<ParameterDecorator>()

export const Url = Meta.createParameterMeta<ParameterDecorator>()
